package com.example.jasonrpc.server.byRegistry;

import com.example.jasonrpc.common.ReflectionUtils;
import com.example.jasonrpc.proto.Peer;
import com.example.jasonrpc.registry.RegistryCenter;
import com.example.jasonrpc.registry.RegistryDirectory;
import com.example.jasonrpc.server.RpcServerAbstract;
import com.example.jasonrpc.server.simple.ServiceInvoker;
import com.example.jasonrpc.server.simple.ServiceManager;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

/**
 * 服务启动应该和rpc服务端启动分开
 * 服务应该先启动再注册，所以将提交注册中心的逻辑放在start里
 */
public class RpcServerByRegistry extends RpcServerAbstract {
    private RpcServerConfigByRegistry config;

    public RpcServerByRegistry(RpcServerConfigByRegistry config) {
        this.net = ReflectionUtils.newInstance(config.getTransportClass());
        this.net.init(config.getPort(), this.handler);
        this.encoder = ReflectionUtils.newInstance(config.getEncoderClass());
        this.decoder = ReflectionUtils.newInstance(config.getDecoderClass());
        //服务
        this.manager = new ServiceManager();
        this.invoker = new ServiceInvoker();
        this.config = config;
    }

    @Override
    public void start() {
        //把所有已注册的服务提交到注册中心
        List<RegistryDirectory> directories = getAllRegisterServices();
        RegistryCenter center = config.getCenter();
        center.registerAll(directories);
        net.start();
    }

    @Override
    public void stop() {
        net.stop();
        //从注册中心删除所有已注册的服务
        List<RegistryDirectory> directories = getAllRegisterServices();
        RegistryCenter center = config.getCenter();
        center.unregisterAll(directories);
    }

    /**
     * 获取所有已在本机注册的服务
     */
    private List<RegistryDirectory> getAllRegisterServices() {
        List<RegistryDirectory> directories = new ArrayList<>();
        List<String> registerServices = manager.getRegisterServices();
        for (String registerService : registerServices) {
            String localLanAddress = getLocalLanAddress();
            RegistryDirectory directory = new RegistryDirectory();
            directory.setPeers(Collections.singletonList(new Peer(localLanAddress, config.getPort())));
            directory.setServiceClass(registerService);
            directories.add(directory);
        }
        return directories;
    }

    /**
     * 获取本机局域网ip，获取失败时中断
     */
    private String getLocalLanAddress() {
        try {
            String addr = "";
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface element = interfaces.nextElement();
                Enumeration<InetAddress> inetAddresses = element.getInetAddresses();
                while (inetAddresses.hasMoreElements()) {
                    InetAddress inetAddress = inetAddresses.nextElement();
                    if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
                        addr = inetAddress.getHostAddress();
                    }
                }
            }
            if (addr.isEmpty()) {
                throw new IllegalStateException("ipv4 lan address not found!");
            }
            return addr;
        } catch (SocketException e) {
            log.warn("ipv4 lan address not found by error!", e);
            throw new IllegalStateException(e);
        }
    }
}
